#include <misc_utils.h>
#include <chord.h>
#include "incognito_proto.h"
#include <id_utils.h>
#include "rpclib.h"
#include <dhash_common.h>
#include <dhblock.h>


u_int64_t starttime;
chord_node dst;

void test_store_cb(ptr<incognito_store_arg> sa, clnt_stat err)
{	
	if (err)
	{
		fatal << "test_store RPC failed: " << err << "\n";
		return;
	}
	warnx << "test_store_cb() - RPC CALLBACK!!\n";
	warnx << "test_store_cb() - err: <" << err << ">\n";
	warnx << "dst.x=" << dst.x << "\n";
	warnx << "time: " << (getusec () -starttime)/1000 << " msec\n";
	exit(0);
}

void test_store(str data)
{
	warnx << "test_store()\ndata.len()=" << data.len() << "\n";
	ptr<incognito_store_arg> sa = New refcounted<incognito_store_arg> ();
	sa->data.setsize(data.len());
	memcpy(sa->data.base(),data.cstr(),data.len());
	sa->key_type = DHASH_CONTENTHASH;
	sa->key_value = compute_hash(data.cstr(),data.len());
	warnx << "test_store(): sa->key_value =" << sa->key_value  << "\n";
	starttime = getusec ();
	doRPC (dst, incognito_program_1,
		INCOGNITOPROC_STORE, sa, NULL, wrap (&test_store_cb, sa));
}
void test_store_noauth(bigint id,str data)
{
	warnx << "test_store_noauth\ndata.len()=" << data.len() << "\n";
	ptr<incognito_store_arg> sa = New refcounted<incognito_store_arg> ();
	sa->data.setsize(data.len());
	memcpy(sa->data.base(),data.cstr(),data.len());
	sa->key_type = DHASH_NOAUTH;
	sa->key_value = id;
	warnx << "test_store(): sa->key_value =" << sa->key_value  << "\n";
	starttime = getusec ();
	doRPC (dst, incognito_program_1,
		INCOGNITOPROC_STORE, sa, NULL, wrap (&test_store_cb, sa));
}

void test_fetch_cb(ptr<incognito_fetch_arg> arg, incognito_fetch_res *res, clnt_stat err);
void test_fetch(bigint id,bool contenthash=true)
{
	incognito_fetch_res *res=New incognito_fetch_res;
	ptr<incognito_fetch_arg> arg = New refcounted<incognito_fetch_arg> ();
	if (contenthash)
		arg->key_type = DHASH_CONTENTHASH;
	else
		arg->key_type = DHASH_NOAUTH;
	arg->key_value = id;
	starttime = getusec ();
	doRPC (dst, incognito_program_1,
		INCOGNITOPROC_FETCH, arg, res, wrap (&test_fetch_cb, arg, res));
}
void test_fetch_cb(ptr<incognito_fetch_arg> arg, incognito_fetch_res *res, clnt_stat err)
{
	warnx << "test_fetch_cb(): - err=" << err << "\n";
	warnx << "test_fetch_cb(): - arg->key_type=" << arg->key_type << "\n";
	warnx << "test_fetch_cb(): - arg->key_value=" << arg->key_value << "\n";
	warnx << "test_fetch_cb(): - res->data=" << str(res->data.base(),res->data.size())  << "\n";
	warnx << "dst.x=" << dst.x << "\n";
	warnx << "time: " << (getusec () -starttime)/1000 << " msec\n";
	exit(0);
}

int main (int argc, char *argv[]) {
	srand (time(NULL));
	if ((argc != 5) && (argc != 6)) 
		fatal << "Usage: " << argv[0] << " host port (fetch key)|(store data)|(nfetch key)|(nstore key data)\n";

	if (inet_addr (argv[1]) == INADDR_NONE) {
		// yep, this still blocks.
		struct hostent *h = gethostbyname (argv[1]);
		if (!h)
			fatal << "Invalid address or hostname: " << argv[1] << "\n";
		struct in_addr *ptr = (struct in_addr *) h->h_addr;
		dst.r.hostname = inet_ntoa (*ptr);
	} else {
		dst.r.hostname = argv[1];
	}

	dst.r.port = atoi (argv[2]);
	dst.x = make_chordID (dst.r.hostname, dst.r.port);
	dst.vnode_num = 0;

	if (!strcmp(argv[3],"fetch")) {
		warn << "fetch\n";
		bigint id;
		str2chordID(argv[4], id);
		test_fetch(id);
	} else if (!strcmp(argv[3],"store")) {
		warn << "store\n";
		test_store(argv[4]);
	} else if (!strcmp(argv[3],"nfetch")) {
		warn << "fetch\n";
		bigint id;
		str2chordID(argv[4], id);
		test_fetch(id,false);
	} else if (!strcmp(argv[3],"nstore")) {
		warn << "nstore\n";
		bigint id;
		str2chordID(argv[4], id);
		test_store_noauth(id,argv[5]);
	} else {
		warn << "unknown param\n";
	}

	amain ();
}
